using System;
using Server;
using Server.Multis;
using Server.Network;
using Server.Regions;

namespace Server.Items
{
	public class Blocker : Item
	{
		public override int LabelNumber{ get{ return 503057; } } // Impassable!

		[Constructable]
		public Blocker() : base( 0x21A4 )
		{
			Movable = false;
		}

		public Blocker( Serial serial ) : base( serial )
		{
		}

		protected override Packet GetWorldPacketFor( NetState state ) {
			Mobile mob = state.Mobile;

			if ( mob != null && mob.AccessLevel >= AccessLevel.GameMaster )
				return new GMItemPacket( this );

			return base.GetWorldPacketFor( state );
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );

			writer.Write( (int) 0 );
		}

		public override void Deserialize( GenericReader reader )
		{
			base.Deserialize( reader );

			int version = reader.ReadInt();
		}

		public sealed class GMItemPacket : Packet
		{
			public GMItemPacket( Item item ) : base( 0x1A )
			{
				this.EnsureCapacity( 20 );

				// 14 base length
				// +2 - Amount
				// +2 - Hue
				// +1 - Flags

				uint serial = (uint)item.Serial.Value;
				int itemID = 0x1183;
				int amount = item.Amount;
				Point3D loc = item.Location;
				int x = loc.X;
				int y = loc.Y;
				int hue = item.Hue;
				int flags = item.GetPacketFlags();
				int direction = (int)item.Direction;

				if ( amount != 0 )
					serial |= 0x80000000;
				else
					serial &= 0x7FFFFFFF;

				m_Stream.Write( (uint) serial );
				m_Stream.Write( (short) (itemID & 0x7FFF) );

				if ( amount != 0 )
					m_Stream.Write( (short) amount );

				x &= 0x7FFF;

				if ( direction != 0 )
					x |= 0x8000;

				m_Stream.Write( (short) x );

				y &= 0x3FFF;

				if ( hue != 0 )
					y |= 0x8000;

				if ( flags != 0 )
					y |= 0x4000;

				m_Stream.Write( (short) y );

				if ( direction != 0 )
					m_Stream.Write( (byte) direction );

				m_Stream.Write( (sbyte) loc.Z );

				if ( hue != 0 )
					m_Stream.Write( (ushort) hue );

				if ( flags != 0 )
					m_Stream.Write( (byte) flags );
			}
		}
	}

    public class LOSBlocker : Item
    {
        public static void Initialize()
        {
            TileData.ItemTable[0x21A2].Flags = TileFlag.Wall | TileFlag.NoShoot;
            TileData.ItemTable[0x21A2].Height = 20;
        }

        public override string DefaultName
        {
            get { return "no line of sight"; }
        }

        [Constructable]
        public LOSBlocker(): base(0x21A2)
        {
            Movable = false;
        }

        public LOSBlocker(Serial serial): base(serial)
        {
        }

        protected override Packet GetWorldPacketFor(NetState state)
        {
            Mobile mob = state.Mobile;

            if (mob != null && mob.AccessLevel >= AccessLevel.GameMaster)
            {
                return new GMItemPacket(this);
            }

            return base.GetWorldPacketFor(state);
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            writer.Write((int)1);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();

            if (version < 1 && ItemID == 0x2199)
                this.ItemID = 0x21A2;
        }

        public sealed class GMItemPacket : Packet
        {
            public GMItemPacket(Item item): base(0x1A)
            {
                this.EnsureCapacity(20);

                // 14 base length
                // +2 - Amount
                // +2 - Hue
                // +1 - Flags

                uint serial = (uint)item.Serial.Value;
                int itemID = 0x36FF;
                int amount = item.Amount;
                Point3D loc = item.Location;
                int x = loc.X;
                int y = loc.Y;
                int hue = item.Hue;
                int flags = item.GetPacketFlags();
                int direction = (int)item.Direction;

                if (amount != 0)
                    serial |= 0x80000000;
                else
                    serial &= 0x7FFFFFFF;

                m_Stream.Write((uint)serial);
                m_Stream.Write((short)(itemID & 0x7FFF));

                if (amount != 0)
                    m_Stream.Write((short)amount);

                x &= 0x7FFF;

                if (direction != 0)
                    x |= 0x8000;

                m_Stream.Write((short)x);

                y &= 0x3FFF;

                if (hue != 0)
                    y |= 0x8000;

                if (flags != 0)
                    y |= 0x4000;

                m_Stream.Write((short)y);

                if (direction != 0)
                    m_Stream.Write((byte)direction);

                m_Stream.Write((sbyte)loc.Z);

                if (hue != 0)
                    m_Stream.Write((ushort)hue);

                if (flags != 0)
                    m_Stream.Write((byte)flags);
            }
        }
    }

    public class NoHousingItem : Item
    {
        private NoHousingDelayTimer m_Timer;
        private Rectangle3D[] m_Area;
        private SimpleNoHousingRegion m_Region;

        [Constructable]
        public NoHousingItem(BaseHouse house): base(0x2FD5)
        {
            m_Timer = new NoHousingDelayTimer(this);
            m_Timer.Start();

            m_Area = house.Region.Area;
            m_Region = new SimpleNoHousingRegion(house.Region.Map, m_Area);
            m_Region.Register();

            Visible = false;
            Movable = false;
        }

        public NoHousingItem(Serial serial): base(serial)
        {
        }

        public override void OnAfterDelete()
        {
            if (m_Region != null)
                m_Region.Unregister();

            if (m_Timer != null && m_Timer.Running)
                m_Timer.Stop();
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            writer.Write((int)0); // version

            if (m_Timer != null)
                writer.Write(m_Timer.Next);
            else
                writer.Write(DateTime.Now);

            writer.Write(m_Area.Length);

            foreach (Rectangle3D rect in m_Area)
                writer.Write(rect);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();

            DateTime next = reader.ReadDateTime();
            m_Area = new Rectangle3D[reader.ReadInt()];

            for (int i = 0; i < m_Area.Length; i++)
                m_Area[i] = reader.ReadRect3D();

            m_Region = new SimpleNoHousingRegion(Map, m_Area);
            m_Region.Register();

            if (next < DateTime.Now)
            {
                m_Timer = new NoHousingDelayTimer(this, next - DateTime.Now);
                m_Timer.Start();
            }
            else
                Delete();
        }

        private class SimpleNoHousingRegion : BaseRegion
        {
            public SimpleNoHousingRegion(Map map, Rectangle3D[] area): base(null, map, Region.DefaultPriority, area)
            {
            }

            public override bool AllowHousing(Mobile from, Point3D p)
            {
                return false;
            }
        }

        private class NoHousingDelayTimer : Timer
        {
            public static TimeSpan DefaultDelay { get { return TimeSpan.FromMinutes(Utility.RandomMinMax(60, 120)); } }

            private NoHousingItem m_Item;

            public NoHousingDelayTimer(NoHousingItem item): this(item, DefaultDelay)
            {
            }

            public NoHousingDelayTimer(NoHousingItem item, TimeSpan delay): base(delay)
            {
                m_Item = item;
                Priority = TimerPriority.OneMinute;
            }

            protected override void OnTick()
            {
                if (m_Item != null && !m_Item.Deleted)
                    m_Item.Delete();
            }
        }
    }
}